#define BDB_HEAD_SIZE     128
#define BDB_IDX_NAME_SIZE 128
#define BDB_FPA_SIZE      256
#define DEF_BDB_MINKEY    2
#define DEF_BDB_PAGE_SIZE 512
#define DEF_BDB_ALIGN     4
#define DEF_BDB_SUFFIX    "idx"
#define BDB_HEAD_MAGIC    0x76543210
struct bparam{
    int pgsiz;
	int minkey;
	int align;
	int pcache_maxbytes;
	int pcache_nbucket;
	int pcache_swapratio;
	int lcache_maxbytes;
	int lcache_nbucket;
	int lcache_swapratio;
};
struct bpg{//btree inner page
   uint64 left;
   int16 lower;
   int16 upper;
   int16 index[1];
};
#define BPHEADSIZ (sizeof(uint64)+sizeof(int16)+sizeof(int16))
struct bidx{
   int32 ksiz;
   uint16 fap;
#define B_VOFLOW 0x100
#define B_PKOFLOW 0x200
#define B_VDUP 0x400
#define B_FMASK 0xFF00
#define B_PMASK 0x00FF
   uint64 offset;
};
#define BIHEADSIZ (sizeof(int32)+sizeof(int16)+sizeof(uint64))
struct blf{//btree leaf
   uint64 pre;
   uint64 next;
   int16 lower;
   int16 upper;
   int16 index[1];
};
#define BLHEADSIZ (sizeof(uint64)+sizeof(uint64)+sizeof(int16)+sizeof(int16))
#define ISBLEAF(off) (off&1)
#define OFFSET(off) (off&~1)
#define BLEAF(off) (off|1)
struct brec{
    int32 ksiz;
	int64 sop;//vsiz or pgno
	int16 fap;
};
#define BRHEADSIZ (sizeof(int32)+sizeof(int64)+sizeof(int16))
#define BRKVSIZ(ksiz,vsiz) (BRHEADSIZ+ksiz+vsiz)
#define BRKSIZ(ksiz) (BRHEADSIZ+sizeof(uint64)+ksiz)
struct vdpg{//value duplicate page
    uint64 nextpg;
	uint64 prepg;
	int16 upper;
	int16 lower;
	int16 index[1];
};
#define VDHEADSIZ (sizeof(uint64)+sizeof(uint64)+sizeof(uint16)+sizeof(uint16))
struct valpiece{
    int32 vsiz;//vsiz indicate whether this page is a overflow page
};
#define MINVSIZ (sizeof(int32)+sizeof(uint64))
#define VP_OSIZ (db->Bpgsiz-VDHEADSIZ-sizeof(int32))
/*struct opg{//overflow head page
    uint64 nextpg;
	int32 siz;
	//int32 ref;
};*/
//#define OHHEADSIZ (sizeof(uint64)+sizeof(int32)+sizeof(int32))
struct opg{//overflow page
    uint64 nextpg;
	int32 siz;
};
#define OPHEADSIZ (sizeof(uint64)+sizeof(int32))
#define OPREFERRED(op) ((op)->nextpg&2)
#define OPREFER(op) ((op)->nextpg|=2)
#define OPUNREFER(op) ((op)->nextpg&=~2)
#define OPNEXTPG(op) ((op)->nextpg&~2)
struct bhd{
    uint32 magic;
    int32 nrec;
	int32 minkey;
	int32 align;
	int32 pgsiz;
	uint64 root;
	uint64 lmost;
	uint64 rmost;
	uint64 maxpg;
	uint64 flast;
	int32 nfpg;
	int32 fstart;
	int32 fend;
	int32 fnum;
	uint64 fread;
};
struct bpstack{
    uint64 offset;
	int16 idxoff;
};
struct bc{//btree cursor
    uint64 offset;
	int16 idxoff;
	void *p;
};
struct biter{
    uint16 flag;
#define BI_INUSE 1
#define BI_END   2
#define BI_INCLUDE 4
#define BI_BACKWORD 8
    uint64 offset;
	int32 idxoff;
	uint64 voffset;
	int32 voff;
	pthread_mutex_t lock;
};
struct bdb{
    int fd;
	FILE *fp;
	struct cache *lcc;
	struct cache *pcc;
	struct bhd *head;
	struct bpstack *stack;
#define DEF_BDB_LEVEL 16
	int ssiz;
	int snum;
	int clock;
	int osiz;
	int16 dir;//indicate keys decrease or increase
	uint64 lastpg;
	uint64 *fpa;
	char *dname;
	struct biter iter;
	pthread_rwlock_t rwlock;
	int flag;
#define BDB_IN_TRANSACTION 1
	struct stack *newpg;
	struct stack *delpg;
#define Bnrec head->nrec
#define Bmaxpg head->maxpg
#define Bflast head->flast
#define Bminkey head->minkey
#define Balign head->align
#define Bpgsiz head->pgsiz
#define Broot head->root
#define Brmost head->rmost
#define Blmost head->lmost
#define Bnfpg head->nfpg
#define Bfstart head->fstart
#define Bfend head->fend
#define Bfnum head->fnum
#define Bfread head->fread
};
#define BDB_TRANSACTION_IN(db) (db)->flag&BDB_IN_TRANSACTION
#define BDB_TRANSACTION_SET(db) (db)->flag|=BDB_IN_TRANSACTION
#define BDB_TRANSACTION_UNSET(db) (db)->flag&=~BDB_IN_TRANSACTION
int adddupval(struct bdb *db,struct blf *lf,int16 ipos,char *val,int vsiz);
int dellfval(struct bdb *db,struct blf *lf,int ipos);
int needdeloverflowpage(struct bdb *db,int ksiz,int vsiz);
uint64 putvdup(struct bdb *db,uint64 off,char *val,int vsiz);
int bputrec(struct bdb *db,struct blf *lf,struct brec *rec,int rsiz);
int bsplitleaf(struct bdb *db,struct blf *lf,int ipos,struct brec *rec,int rsiz,struct blf* rlf);
int bsplitpage(struct bdb *db,struct bpg* p,int ipos,struct bidx *idx,int isiz,struct bpg* rp,struct bidx** ridx,int *rsiz);
int bputidx(struct bdb *db,struct bpg* p,int snum,struct bidx *idx,int isiz);
int bdelrec(struct bdb *db,struct blf *lf,int snum);
int bdelidx(struct bdb *db,int snum);
int delopg(struct bdb *db,uint64 off);
int findspecial(struct bdb *db,uint64 off,char *val,int vsiz,struct bc *cursor);
int delspecialval(struct bdb *db,uint64 off,char *val,int vsiz,uint64 *noff);
int deldupval(struct bdb *db,uint64 off);
int jump(struct bdb *db,char *key,int ksiz,uint64 *offset,int *idxoff,int flag);
int bshrinkpage(struct bdb *db);

struct bdb* bopen(char *dbname,char *iname,int seq,uint32 flag,struct bparam* param);
struct bdb* bdbopen(char *file,int flag,struct bparam* param);
int bput(struct bdb *db,char *key,int ksiz,char *val,int vsiz,int flag);
int bclose(struct bdb *db);
int bdelete(struct bdb* db);
int bget(struct bdb *db,struct bstring *key,struct strlist **list);
int berase(struct bdb *db,char *key,int ksiz,char *val,int vsiz);
int biterinit(struct bdb* db,char *key,int ksiz,int flag);
int biternext(struct bdb *db,struct bstring **key,struct bstring **val);
int biterclose(struct bdb *db);
int btraverse(struct bdb* db);
struct bstring* colname(struct bdb* db,int *seq);
int bgettohash(struct bdb *db,char *key, int ksiz,struct harray **ha);

int bdbtrans_beg(struct bdb* db);
int bdbtrans_commit(struct bdb *db);
int bdbtrans_abort(struct bdb *db);
int bdbtrans_cancel(struct bdb* db);
